﻿//4.13 调用者信心属性（C# 5）
//从C# 5开始，可以给可选参数添加3个调用者信息属性中的一个，它们可以让编译器从调用者源代码获取参数的默认值：
//    [CallerMemberName] 表示调用者的成员的名称
//    [CallerFilePath] 表示调用者的源代码文件路径
//    [CallerLineNumber] 表示调用者源代码文件的行号

using System;
using System.Runtime.CompilerServices;
//下面代码的Foo方法演示了这3个属性：
namespace _141_属性_调用者信息属性_CSharp5_
{
    class Program
    {
        static void Foo(
            [CallerMemberName] string memberName = null,
            [CallerFilePath] string filePath = null,
            [CallerLineNumber] int lineNumber = 0)
        {
            Console.WriteLine(memberName);
            Console.WriteLine(filePath);
            Console.WriteLine(lineNumber);
        }
        static void Main(string[] args)
        {
            Foo();
            //假设我们的程序位于c:\source\test\Program.cs，那么输出结果是：
            //Main
            //c:\source\test\Program.cs
            //8

            //和标准的可选参数一样，替代操作在调用位置完成。因此，方法的语法是这样：
            /*
            static void Main()
            {
                Foo("Main", @"c:\source\test\Program.cs", 8);
            }
            */

            Console.ReadKey();
        }
    }
    //调用者信息属性很适合用于记录日志以及实现一些模式。如当一个对象的某个属性发生变化时，触发一个变化通知事件。事实上.NET框架有一个专门实现这个效果的标准接口INotifyPropertyChanged(位于System.ComponentModel)：
    public interface INotifyPropertyChanged
    {
        event PropertyChangedEventHandler PropertyChanged;
    }
    public delegate void PropertyChangedEventHandler(object sender, PropertyChangedEventArgs e);
    public class PropertyChangedEventArgs : EventArgs
    {
        public PropertyChangedEventArgs(string propertyName) { }
        public virtual string PropertyName { get; }
    }
    //注意，PropertyChangedEventArgs方法需要接受发生变化的属性的名称。然而，通过使用[CallerMemberName]属性，就可以实现这个接口，并且不需要指定属性名称即可调用这个事件：
    public class Foo : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged = delegate { };
        void RaisePropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        string customerName;
        public string CustomerName
        {
            get { return customerName; }
            set
            {
                if (value == customerName) return;
                customerName = value;
                RaisePropertyChanged();
                // 编译器会将上面一行代码转换为：
                // RaisePropertyChanged("CustomerName");
            }
        }
    }
}
